﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Mechanical;
using Autodesk.Revit.DB.Plumbing;
using Autodesk.Revit.UI;
using YArchitech.Revit;
using SystemDiagramNew.TypeDefinition;

namespace SystemDiagramNew.Utils
{
	public static class RevitUtils
	{
		public static IEnumerable<Element> ToEnumerable(this ElementSet elements)
		{
			if (elements != null)
			{
				return elements.OfType<Element>();
			}
			return Enumerable.Empty<Element>();
		}

		public static bool IsPressurePiping(this MEPSystem mepSystem)
		{
            return !(mepSystem is PipingSystem) || (int)((PipingSystem)mepSystem).SystemType == 16;
		}

		internal static FillPatternElement GetSolidPattern(this Document doc, string patternName)
		{
			return doc.GetElements<FillPatternElement>().FirstOrDefault((FillPatternElement fp) => string.CompareOrdinal(fp.Name, patternName) == 0);
		}

		public static ExternalCommandData CommandData { get; set; }

		public static UIApplication UIApplication
		{
			get
			{
				return RevitUtils.CommandData.Application;
			}
		}

		public static UIDocument UIDocument
		{
			get
			{
				return RevitUtils.UIApplication.ActiveUIDocument;
			}
		}

		public static Document Document
		{
			get
			{
				return RevitUtils.UIDocument.Document;
			}
		}

		public static bool Set(this Element element, BuiltInParameter builtInParameter, string value)
		{
			Parameter parameter = element.get_Parameter(builtInParameter);
			return parameter != null && parameter.Set(value);
		}

		public static bool Set(this Element element, BuiltInParameter builtInParameter, int value)
		{
			Parameter parameter = element.get_Parameter(builtInParameter);
			return parameter != null && parameter.Set(value);
		}

		public static bool Set(this Element element, BuiltInParameter builtInParameter, double value)
		{
			Parameter parameter = element.get_Parameter(builtInParameter);
			return parameter != null && parameter.Set(value);
		}

		public static bool Set(this Element element, BuiltInParameter builtInParameter, ElementId value)
		{
			Parameter parameter = element.get_Parameter(builtInParameter);
			return parameter != null && parameter.Set(value);
		}

		public static int GetDiameter(this Pipe pipe)
		{
			Parameter parameter = pipe.get_Parameter(BuiltInParameter.RBS_PIPE_DIAMETER_PARAM);
			if (parameter == null)
			{
				return 0;
			}
			return RevitUtils.GetParameterMMValue(parameter);
		}

		public static Size GetSize(this Duct duct)
		{
			Parameter param = duct.get_Parameter(BuiltInParameter.RBS_CURVE_HEIGHT_PARAM);
			return new Size(RevitUtils.GetParameterMMValue(duct.get_Parameter(BuiltInParameter.RBS_CURVE_WIDTH_PARAM)), RevitUtils.GetParameterMMValue(param));
		}

		public static int GetParameterMMValue(Parameter param)
		{
			if (param == null)
			{
				return 0;
			}
            if ((int)param.DisplayUnitType == 2)
			{
				string s = param.AsValueString().ToLower().Trim().TrimEnd("mm".ToCharArray()).Trim();
				int result = 0;
				int.TryParse(s, out result);
				return result;
			}
			return Convert.ToInt32(UnitConvert.LengthToInternal(param.AsDouble()) * 1000.0);
		}

		public static bool GetPoints(this MEPCurve curve, out XYZ startPoint, out XYZ endPoint)
		{
			startPoint = null;
			endPoint = null;
			LocationCurve locationCurve = curve.Location as LocationCurve;
			if (locationCurve == null)
			{
				return false;
			}
			startPoint = locationCurve.Curve.GetEndPoint(0);
			endPoint = locationCurve.Curve.GetEndPoint(1);
			return true;
		}

		public static double MMtoFeet(this double mm)
		{
			return UnitConvert.LengthToStd(mm / 1000.0);
		}

		public static double FeettoMM(this double ft)
		{
			return UnitConvert.LengthToInternal(ft) * 1000.0;
		}

		public static int ToInt(this double value)
		{
			return (int)((value * 10.0 + 0.5) / 10.0);
		}

		public static Document GetDocument(this UIApplication uiApp)
		{
			return uiApp.ActiveUIDocument.Document;
		}

		public static Document GetDocument(this ExternalCommandData cmdData)
		{
			return cmdData.Application.GetDocument();
		}

		public static bool ContainsViewDrafting(this Document doc, string viewName)
		{
			return doc.GetElements<ViewDrafting>().Any((ViewDrafting v) => v.ViewName == viewName);
		}

		public static ViewDrafting CreateNewViewDrafting(this Document doc, ref string viewName, int viewScale = 100)
		{
			IEnumerable<string> source = from v in doc.GetElements<ViewDrafting>()
			select v.ViewName;
			while (source.Contains(viewName))
			{
				viewName = viewName.Upgrade();
			}
			ViewDrafting result;
			using (Transaction transaction = new Transaction(doc, "CreateViewDrafting"))
			{
				transaction.Start();
				ViewDrafting viewDrafting = RevitViewExtension.CreateViewDrafting(doc);
				viewDrafting.ViewName = viewName;
				viewDrafting.Scale = viewScale;
				viewDrafting.CropBox = new BoundingBoxXYZ
				{
					Min = new XYZ(-50.0, -50.0, 0.0),
					Max = new XYZ(50.0, 50.0, 0.0)
				};
				transaction.Commit();
				result = viewDrafting;
			}
			return result;
		}

		public static void SetActiveView(this UIDocument uiDoc, Autodesk.Revit.DB.View activeView)
		{
			if (activeView == null)
			{
				return;
			}
			uiDoc.ActiveView = activeView;
			uiDoc.RefreshActiveView();
		}

		public static void UpdateModel(this UIDocument uiDoc, bool autoJoin)
		{
			uiDoc.Document.Regenerate();
			if (autoJoin)
			{
				uiDoc.Document.AutoJoinElements();
			}
			uiDoc.RefreshActiveView();
		}

		public static void UpdateModel(this UIApplication uiApp, bool autoJoin)
		{
			uiApp.ActiveUIDocument.UpdateModel(autoJoin);
		}

		public static void UpdateModel(this ExternalCommandData cmdData, bool autoJoin)
		{
			cmdData.Application.UpdateModel(autoJoin);
		}

		public static List<Level> GetSortLevels(this Document doc, double bottomRange = -1.7976931348623157E+308, double topRange = 1.7976931348623157E+308)
		{
			List<Level> list = (from Level level in new FilteredElementCollector(doc).OfClass(typeof(Level)).ToElements()
			where level.Elevation >= bottomRange && level.Elevation <= topRange
			select level).ToList<Level>();
			list.Sort(new LevelComparer());
			return list;
		}

		public static Level GetCurrentLevel(this UIDocument uiDoc)
		{
			return uiDoc.ActiveView.GenLevel;
		}

		public static Level GetCurrentLevel(this ExternalCommandData cmdData)
		{
			return cmdData.Application.ActiveUIDocument.GetCurrentLevel();
		}

		public static Level GetLevel(this Element element)
		{
			MEPCurve mepcurve = element as MEPCurve;
			if (mepcurve == null)
			{
				return element.GetYJKLevel();
			}
			return mepcurve.ReferenceLevel;
		}

		public static string GetShowName(this MEPSystem mepSystem)
		{
			if (mepSystem == null)
			{
				return "";
			}
			string result;
			try
			{
				ElementId elementId = mepSystem.GetParameter(BuiltInParameter.ELEM_TYPE_PARAM).AsElementId();
				MEPSystemType mepsystemType = mepSystem.Document.GetElementById(elementId) as MEPSystemType;
				result = ((mepsystemType == null) ? mepSystem.Name : string.Format("{0} {1}", mepsystemType.Name, mepSystem.Name));
			}
			catch
			{
				result = mepSystem.Name;
			}
			return result;
		}

		public static IEnumerable<PipingSystem> GetPipingSystems(this Document doc, string systemName, PipeSystemType systemType)
		{
			return from sys in doc.GetElements<PipingSystem>()
			where sys.Name == systemName && sys.SystemType == systemType
			select sys;
		}

		public static IEnumerable<MechanicalSystem> GetMechanicalSystems(this Document doc, string systemName, DuctSystemType systemType)
		{
			return from sys in doc.GetElements<MechanicalSystem>()
			where sys.Name == systemName && sys.SystemType == systemType
			select sys;
		}

		public static MEPSystemClassification GetSystemClass(this MEPSystem mepSystem)
		{
			if (mepSystem is PipingSystem)
			{
                return (MEPSystemClassification)((PipingSystem)mepSystem).SystemType;
			}
			if (mepSystem is MechanicalSystem)
			{
                return (MEPSystemClassification)((MechanicalSystem)mepSystem).SystemType;
			}
			return 0;
		}

		public static IEnumerable<Element> GetAllElements(this PipingSystem pipingSystem)
		{
			if (pipingSystem != null)
			{
				return pipingSystem.Elements.OfType<Element>().Concat(pipingSystem.PipingNetwork.OfType<Element>());
			}
			return Enumerable.Empty<Element>();
		}

		public static IEnumerable<Element> GetAllElements(this MechanicalSystem mechanicalSystem)
		{
			if (mechanicalSystem != null)
			{
				return mechanicalSystem.Elements.OfType<Element>().Concat(mechanicalSystem.DuctNetwork.OfType<Element>());
			}
			return Enumerable.Empty<Element>();
		}

		public static IEnumerable<Element> GetAllElements(this MEPSystem mepSystem)
		{
			if (mepSystem is PipingSystem)
			{
				return ((PipingSystem)mepSystem).GetAllElements();
			}
			if (!(mepSystem is MechanicalSystem))
			{
				return Enumerable.Empty<Element>();
			}
			return ((MechanicalSystem)mepSystem).GetAllElements();
		}

		public static IEnumerable<Element> GetAllSystemElementsInLinkDocuments(this MEPSystem mepSystemInCurdocument)
		{
			if (mepSystemInCurdocument == null)
			{
				return Enumerable.Empty<Element>();
			}
			if (mepSystemInCurdocument is PipingSystem)
			{
				return RevitUtils.GetAllSystemElementsInLinkDocuments((PipingSystem)mepSystemInCurdocument);
			}
			if (mepSystemInCurdocument is MechanicalSystem)
			{
				return RevitUtils.GetAllSystemElementsInLinkDocuments((MechanicalSystem)mepSystemInCurdocument);
			}
			return Enumerable.Empty<Element>();
		}

		public static IEnumerable<Element> GetAllSystemElementsInLinkDocuments(PipingSystem mepSystemInCurdocument)
		{
			IEnumerable<Element> result = Enumerable.Empty<Element>();
			if (mepSystemInCurdocument == null)
			{
				return result;
			}
			Document document = mepSystemInCurdocument.Document;
			if (document == null)
			{
				return result;
			}
			IEnumerable<LinkedDocument> linkedDocuments = document.GetLinkedDocuments();
			if (linkedDocuments == null || !linkedDocuments.Any<LinkedDocument>())
			{
				return result;
			}
			return from lnkDoc in linkedDocuments
			from sys in lnkDoc.Document.GetPipingSystems(mepSystemInCurdocument.Name, mepSystemInCurdocument.SystemType)
			from elem in sys.GetAllElements()
			where elem != null
			select elem;
		}

		public static IEnumerable<Element> GetAllSystemElementsInLinkDocuments(MechanicalSystem mepSystemInCurdocument)
		{
			IEnumerable<Element> result = Enumerable.Empty<Element>();
			if (mepSystemInCurdocument == null)
			{
				return result;
			}
			Document document = mepSystemInCurdocument.Document;
			if (document == null)
			{
				return result;
			}
			IEnumerable<LinkedDocument> linkedDocuments = document.GetLinkedDocuments();
			if (linkedDocuments == null || !linkedDocuments.Any<LinkedDocument>())
			{
				return result;
			}
			return from lnkDoc in linkedDocuments
			from sys in lnkDoc.Document.GetMechanicalSystems(mepSystemInCurdocument.Name, mepSystemInCurdocument.SystemType)
			from elem in sys.GetAllElements()
			where elem != null
			select elem;
		}

		public static double MinPipeLength
		{
			get
			{
				return 500.0.MMtoFeet();
			}
		}

		public static TextNoteType CreateTextNoteType(this Document document)
		{
			return document.CreateTextNoteType(2.5, 0.7, "宋体");
		}

		public static TextNoteType CreateTextNoteType(this Document document, double textHeight, double widthFactor, string fontName)
		{
			double num = textHeight.MMtoFeet();
			string newName = textHeight.ToString("F2") + " mm " + fontName;
			IEnumerable<TextNoteType> elements = document.GetElements<TextNoteType>();
			if (!elements.Any<TextNoteType>())
			{
				return null;
			}
			TextNoteType textNoteType = elements.FirstOrDefault((TextNoteType t) => t.Name == newName) ?? elements.First<TextNoteType>();
			if (textNoteType == null)
			{
				return null;
			}
			Parameter parameter = textNoteType.get_Parameter(BuiltInParameter.TEXT_SIZE);
			if (parameter == null)
			{
				return textNoteType;
			}
			double val = parameter.AsDouble();
			Parameter parameter2 = textNoteType.get_Parameter(BuiltInParameter.TEXT_WIDTH_SCALE);
			if (parameter2 == null)
			{
				return textNoteType;
			}
			double val2 = parameter2.AsDouble();
			if (Geometry.IsEqual(num, val, 0.001) && Geometry.IsEqual(widthFactor, val2, 0.001))
			{
				return textNoteType;
			}
			TextNoteType textNoteType2 = textNoteType.Duplicate(newName) as TextNoteType;
			if (textNoteType2 == null)
			{
				return null;
			}
			textNoteType2.get_Parameter(BuiltInParameter.TEXT_SIZE).Set(num);
			textNoteType2.get_Parameter(BuiltInParameter.TEXT_WIDTH_SCALE).Set(widthFactor);
			textNoteType2.get_Parameter(BuiltInParameter.LEADER_OFFSET_SHEET).Set(0.0);
			return textNoteType2;
		}

		public static double GetTextNoteLength(this string text)
		{
			if (string.IsNullOrEmpty(text) || text.Length == 0)
			{
				return 0.0;
			}
			Encoding encoding = new ASCIIEncoding();
			double num = 0.0;
			byte[] bytes = encoding.GetBytes(text);
			for (int i = 0; i < bytes.Length; i++)
			{
				if (bytes[i] == 63)
				{
					num += 2.0;
				}
				else
				{
					num += 1.0;
				}
			}
			return num;
		}

		public static TextNote CreateTextNote(this Autodesk.Revit.DB.View drawView, string text, XYZ ptTextCenter)
		{
			return drawView.CreateTextNote(text, ptTextCenter, new XYZ(1.0, 0.0, 0.0));
		}

		public static TextNote CreateTextNote(this Autodesk.Revit.DB.View drawView, string text, XYZ ptTextCenter, XYZ drawVec)
		{
			if (string.IsNullOrEmpty(text))
			{
				return null;
			}
			double num = 2.5.MMtoFeet();
			double num2 = text.GetTextNoteLength() * num * 0.7;
			XYZ xy = drawVec.GetXY();
			XYZ perpendicularVector = xy.GetPerpendicularVector();
			XYZ xyz = ptTextCenter.GetXY();
			string versionNumber = drawView.Document.Application.VersionNumber;
			bool flag = versionNumber.Contains("2014");
			bool flag2 = versionNumber.Contains("2015");
			if (flag2)
			{
				num2 *= 1.3;
			}
			if (!flag && !flag2)
			{
				xyz = ptTextCenter.GetXY() + 0.5 * num * perpendicularVector * (double)drawView.Scale;
			}
            TextAlignFlags textAlign = (TextAlignFlags)1152;
			TextNote textNode = drawView.Document.GetTextNode(drawView, xyz, new XYZ(1.0, 0.0, 0.0), new XYZ(0.0, 1.0, 0.0), num2, textAlign, text);
			if (textNode != null)
			{
				textNode.TextNoteType = drawView.Document.CreateTextNoteType();
				double num3 = xy.AngleTo(XYZ.BasisX);
				Line line = Line.CreateUnbound(xyz, XYZ.BasisZ);
				ElementTransformUtils.RotateElement(drawView.Document, textNode.Id, line, num3);
				Document document = textNode.Document;
				new XYZ(1.0, 0.0, 0.0);
			}
			return textNode;
		}

		public static string GetPipeDiameterPrefix(this Element elem)
		{
            if ((int)elem.GetSystemClass() != 16)
			{
				return "DN";
			}
			return "De";
		}

		public static DetailCurve NewDetailLine(this Autodesk.Revit.DB.View drawView, XYZ start, XYZ end)
		{
			DetailCurve result;
			try
			{
				result = drawView.Document.Create.NewDetailCurve(drawView, Line.CreateBound(start, end));
			}
			catch
			{
				result = null;
			}
			return result;
		}

		public static DetailCurve NewDetailCircle(this Autodesk.Revit.DB.View drawView, XYZ center, double radius)
		{
			DetailCurve result;
			try
			{
				result = drawView.Document.Create.NewDetailCurve(drawView, Arc.Create(center, radius, 0.0, Math.PI*2, XYZ.BasisX, XYZ.BasisY));
			}
			catch
			{
				result = null;
			}
			return result;
		}

		public static DetailCurve NewDetailBottomHalfCircle(this Autodesk.Revit.DB.View drawView, XYZ center, double radius)
		{
			DetailCurve result;
			try
			{
				result = drawView.Document.Create.NewDetailCurve(drawView, Arc.Create(center, radius, Math.PI, Math.PI*2, XYZ.BasisX, XYZ.BasisY));
			}
			catch
			{
				result = null;
			}
			return result;
		}

		public static DetailCurve NewDetailTopHalfCircle(this Autodesk.Revit.DB.View drawView, XYZ center, double radius)
		{
			return drawView.Document.Create.NewDetailCurve(drawView, Arc.Create(center, radius, 0.0, Math.PI, XYZ.BasisX, XYZ.BasisY));
		}

		public const double TextHeight = 2.5;

		public const double TextWidthFactor = 0.7;

		public const string TextName = "宋体";
	}
}
